#include <stdlib.h>

#include "UILog4CXXLogger.h"
#include "CommonUtil.h"
#include "UIOSAL.h"

#include "log4cxx/fileappender.h"
#include "log4cxx/consoleappender.h"
#include "log4cxx/htmllayout.h"
#include "log4cxx/level.h"
#include "log4cxx/patternlayout.h"
#include "log4cxx/propertyconfigurator.h"
#include "log4cxx/helpers/transcoder.h"
#include "log4cxx/helpers/pool.h"
#include "log4cxx/net/xmlsocketappender.h"
#include "log4cxx/net/socketappender.h"
#include "log4cxx/xml/domconfigurator.h"
#include "log4cxx/xml/xmllayout.h"
#include "log4cxx/spi/loggingevent.h"
#include "log4cxx/spi/location/locationinfo.h"

using namespace log4cxx;
using namespace log4cxx::xml;
using namespace log4cxx::spi;
using namespace log4cxx::helpers;
using namespace log4cxx::net;

UILog4CXXLogger::UILog4CXXLogger(void)
{
}

UILog4CXXLogger::~UILog4CXXLogger(void)
{
}

void UILog4CXXLogger::initLogger(std::string configFile)
{
	UIFile config;
	config.openFile(configFile.c_str());
	std::string line;
	
	bool enableSocketAppender = false;
	std::string socketHost = "";
	int socketPort = -1;

	while (config.getLine(line)) {
		trim(line);
		if (startsWith(line, "//") || line.length() == 0) 
			continue;
		if (line.find("=") != std::string::npos) {
			std::vector<std::string> items;
			splitString(line, "=", items);
			if (items.size() == 2) {
				trim(items[0]);
				trim(items[1]);
				
				if (equalsIgnoreCase(items[0], "enableXMLAppender") && equalsIgnoreCase(items[1], "true")) 
				{
					std::string xmlLogFile  = getLogFilePrefix() + ".xml";
					Logger::getRootLogger()->addAppender(new FileAppender(LayoutPtr(new XMLLayout()), Transcoder::decode(xmlLogFile.c_str())));
				}
				else if (equalsIgnoreCase(items[0], "enableHTMLAppender") && equalsIgnoreCase(items[1], "true")) 
				{
					std::string htmlLogFile = getLogFilePrefix() + ".html";
					Logger::getRootLogger()->addAppender(new FileAppender(LayoutPtr(new HTMLLayout()), Transcoder::decode(htmlLogFile.c_str())));
				}
				else if (equalsIgnoreCase(items[0], "enableConsoleAppender") && equalsIgnoreCase(items[1], "true")) 
				{
					PatternLayoutPtr myLayoutPtr = new PatternLayout(Transcoder::decode("%-5p %c %m%n"));
					ConsoleAppenderPtr myConsoleAppenderPtr = new ConsoleAppender(myLayoutPtr);
					myConsoleAppenderPtr->setThreshold(log4cxx::Level::getError());
					Logger::getRootLogger()->addAppender(myConsoleAppenderPtr);
				}
				else if (equalsIgnoreCase(items[0], "enableSocketAppender") && equalsIgnoreCase(items[1], "true")) 
				{
					enableSocketAppender = true;
				}
				else if (equalsIgnoreCase(items[0], "socketAppender.address") && enableSocketAppender)
				{
					socketHost = items[1];
				}
				else if (equalsIgnoreCase(items[0], "socketAppender.port") && enableSocketAppender)
				{
					socketPort = atoi(items[1].c_str());
				}
			}
		}
	}
	config.closeFile();

	if (enableSocketAppender && !socketHost.empty() && socketPort != -1)
		Logger::getRootLogger()->addAppender(new SocketAppender(Transcoder::decode(socketHost.c_str()), socketPort));
}

void UILog4CXXLogger::disable()
{
}

void UILog4CXXLogger::fatal(UIModuleType moduleType, std::string srcObjClassName, std::string message)
{
	logLevel(getModuleName(moduleType)+"."+srcObjClassName, message, Level::getFatal());
}

void UILog4CXXLogger::warn(UIModuleType moduleType, std::string srcObjClassName, std::string message)
{
	logLevel(getModuleName(moduleType)+"."+srcObjClassName, message, Level::getWarn());
}

void UILog4CXXLogger::inf(UIModuleType moduleType, std::string srcObjClassName, std::string message)
{
	logLevel(getModuleName(moduleType)+"."+srcObjClassName, message, Level::getInfo());
}

void UILog4CXXLogger::err(UIModuleType moduleType, std::string srcObjClassName, std::string message)
{
	logLevel(getModuleName(moduleType)+"."+srcObjClassName, message, Level::getError());
}

void UILog4CXXLogger::debug(UIModuleType moduleType, std::string srcObjClassName, std::string message)
{
	logLevel(getModuleName(moduleType)+"."+srcObjClassName, message, Level::getDebug());
}

void UILog4CXXLogger::logLevel(std::string srcObjClassName, std::string message, LevelPtr pLevel)
{
	logLevel(srcObjClassName, "UNKNOWN", -1, message, pLevel);
}

void UILog4CXXLogger::logLevel(std::string srcObjClassName, std::string srcFunctionName, int lineNumber, std::string message, LevelPtr pLevel)
{
		// Get the Logger or use the root logger
	LoggerPtr curLogger;
	if (srcObjClassName.length() > 0) {
		curLogger = Logger::getLogger(srcObjClassName.c_str());
	}

	// Code copied from Category.log methods
	if (curLogger->getLoggerRepository()->isDisabled(pLevel->toInt())) {
		return;
	}

	if (pLevel->isGreaterOrEqual(curLogger->getEffectiveLevel())) {
		// Now build our own LoggingEvent			
		LocationInfo* p_location = new LocationInfo(srcObjClassName.c_str(), srcFunctionName.c_str(), lineNumber);
		LoggingEventPtr logEvent = new LoggingEvent(Transcoder::decode(srcObjClassName.c_str()), pLevel, Transcoder::decode(message.c_str()), *p_location);
		Pool p;
		curLogger->callAppenders(logEvent, p);
	}
}
